/**
 * @file    fileChecker.cpp
 * @author  wuhui1536@gmail.com
 * @date    2025-02-19
 * @brief   文件类型检测器 - 实现文件
 *
 * @details
 * 该文件实现了 FileChecker 类的功能，包括：
 * - 解析 JSON 规则文件
 * - 读取文件头部信息
 * - 通过文件签名匹配文件类型
 *
 * @note
 * 需要确保 JSON 规则文件路径正确，否则无法正确识别文件类型。
 *
 */

#include "fileChecker.h"

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

#include "cJSON.h"
#include "utils.h"

using namespace std;

/**
 * @brief 默认构造函数
 */
FileSignatureRule::FileSignatureRule() : offset(0) {}


bool FileChecker::loadRulesFromJson(const string &filename)
{
    string jsonData = Tool::readJsonFile(filename);
    if (jsonData.empty())
        return false;

    cJSON *root = cJSON_Parse(jsonData.c_str());
    if (!root)
    {
        cerr << "JSON 解析失败" << endl;
        return false;
    }

    cJSON *rulesArray = cJSON_GetObjectItem(root, "rules");
    if (!cJSON_IsArray(rulesArray))
    {
        cJSON_Delete(root);
        return false;
    }

    int ruleCount = cJSON_GetArraySize(rulesArray);
    for (int i = 0; i < ruleCount; ++i)
    {
        cJSON *item = cJSON_GetArrayItem(rulesArray, i);
        if (!cJSON_IsObject(item))
            continue;

        FileSignatureRule rule;
        rule.type = cJSON_GetObjectItem(item, "type")->valuestring;
        rule.offset = cJSON_GetObjectItem(item, "offset")->valueint;
        rule.description = cJSON_GetObjectItem(item, "description")->valuestring;

        // 解析扩展名
        cJSON *extArray = cJSON_GetObjectItem(item, "extension");
        if (cJSON_IsArray(extArray))
        {
            int extCount = cJSON_GetArraySize(extArray);
            for (int j = 0; j < extCount; ++j)
            {
                cJSON *extItem = cJSON_GetArrayItem(extArray, j);
                if (cJSON_IsString(extItem))
                {
                    rule.extensions.push_back(extItem->valuestring);
                }
            }
        }

        // 解析文件签名
        cJSON *sigArray = cJSON_GetObjectItem(item, "signature");
        if (cJSON_IsArray(sigArray))
        {
            int sigCount = cJSON_GetArraySize(sigArray);
            for (int j = 0; j < sigCount; ++j)
            {
                cJSON *sigItem = cJSON_GetArrayItem(sigArray, j);
                if (cJSON_IsString(sigItem))
                {
                    rule.signatures.push_back(sigItem->valuestring);
                }
            }
        }

        rules.push_back(rule);
    }

    cJSON_Delete(root);
    return true;
}

string FileChecker::readFileHeader(const string &filePath, int bytesToRead) const
{
    ifstream file(filePath.c_str(), ios::binary);
    if (!file.is_open())
    {
        cerr << "无法打开文件: " << filePath << endl;
        return "";
    }

    vector<unsigned char> buffer(bytesToRead);
    file.read(reinterpret_cast<char *>(&buffer[0]), bytesToRead);
    file.close();

    stringstream hexStream;
    for (size_t i = 0; i < buffer.size(); i++)
    {
        hexStream << hex << setw(2) << setfill('0') << (int)buffer[i] << " ";
    }
    return hexStream.str();
}

FileChecker::FileChecker(const string &ruleFile)
{
    if (!loadRulesFromJson(ruleFile))
    {
        cerr << "规则文件加载失败！" << endl;
    }
}

string FileChecker::matchFileType(const string &filePath) const
{
    string fileHeader = readFileHeader(filePath);
    if (fileHeader.empty())
        return "Unknown";

    // 将文件头转换为小写
    fileHeader = Tool::toLowerCase(fileHeader);

    for (size_t i = 0; i < rules.size(); i++)
    {
        const FileSignatureRule &rule = rules[i];
        for (size_t j = 0; j < rule.signatures.size(); j++)
        {
            string signature = rule.signatures[j];
            // cerr << "rule.signatures-" << j << " " << signature << endl;

            // 将签名转换为小写
            signature = Tool::toLowerCase(signature);
            if (fileHeader.size() < signature.size())
            {
                continue;
            }

            bool match = true;
            for (size_t k = 0; k < signature.size(); k++)
            {
                // 如果遇到 ??，则跳过当前字符继续匹配下一个字符
                if (signature[k] == '?' || signature[k] == ' ')
                {
                    continue;
                }
                if (fileHeader[rule.offset + k] != signature[k])
                {
                    match = false;
                    break;
                }
            }

            // 如果匹配成功，则返回类型
            if (match)
            {
                return rule.type;
            }
        }
    }
    cerr << "fileHeader[0-15]: " << fileHeader << endl;
    return "Unknown";
}
